#ifndef _TCPSERVERWRAPPER_INC_
#define _TCPSERVERWRAPPER_INC_

#include "Network/Connector.h"
#include "Network/TcpServer.h"
#include "Common/Stream.h"
#include "Cfg.h"
#include "GameClient.h"
#include "HallConnector.h"

typedef std::shared_ptr<Network::TcpConduit> TcpConnection;

namespace Network
{
	class TcpSlaveWrapper:
		public TcpSlaveServerT<GameClient>
	{
	public:
		TcpSlaveWrapper(UInt32 idx): TcpSlaveServerT<GameClient>(idx) {}
		virtual TcpConduit * newConnection(int ss, TcpSlaveServer * s, int id)
		{
			int ssId = -ss;
			if ( ssId <= 0 || ssId > TCP_CONN_IDX_MAX )
				return nullptr;
			switch ( ssId )
			{
			case 1:
				{
					Connector * conn = new(std::nothrow) HallConnector( ss, s, id, cfg.getHallIp(), cfg.getHallPort() );
					return conn;
				}
				break;
			default:
				return nullptr;
			}
		}
	};

	class TcpServerWrapper
	{
	public:
		TcpServerWrapper(UInt16 port, int connCount = 0)
		{
			m_TcpService = new TcpMasterServerT<GameClient, TcpSlaveWrapper>(port);
			ASSERT(m_TcpService != NULL);
			m_Active = true;
			TCP_CONN_IDX_MAX = connCount;
		}

		~TcpServerWrapper()
		{
			delete m_TcpService;
		}

	public:
		inline void Start()
		{
			m_TcpThread.start(*m_TcpService);
		}
		inline void Join()
		{
			m_TcpThread.join();
		}
		inline void UnInit()
		{
			m_Active = false;
			m_TcpService->uninit();
		}

		inline void Close(int sessionID)
		{
			if(!m_Active)
				return;
			m_TcpService->close(sessionID);
		}

		inline void CloseRouter()
		{
			Close( -1 );
		}

		inline void CloseLog()
		{
			Close( -2 );
		}

		inline TcpConnection GetConn(int sessionID)
		{
			if(!m_Active)
				return TcpConnection();
			return m_TcpService->find(sessionID);
		}

	public:
		template <typename MsgType>
		void SendMsgToClient(int sessionID, MsgType& msg)
		{
			if(!m_Active)
				return;
			TcpConnection conn = GetConn(sessionID);
			if(conn.get() == nullptr)
				return;
			std::vector<UInt8> buffer;
			msg.BuildHeader(buffer);
			msg.Serialize(buffer);
			msg.FixHeader(buffer);
			conn->send(&buffer[0], buffer.size());
		}

		template <typename MsgType>
		void SendMsgToClient(TcpConduit * conduit, MsgType& msg)
		{
			if(!m_Active)
				return;
			std::vector<UInt8> buffer;
			msg.BuildHeader(buffer);
			msg.Serialize(buffer);
			msg.FixHeader(buffer);
			conduit->send(&buffer[0], buffer.size());
		}

		void SendMsgToClient(int sessionID, const void * buffer, UInt16 size)
		{
			if(!m_Active)
				return;
			TcpConnection conn = m_TcpService->findConn(sessionID);
			if(conn.get() == nullptr)
				return;
			conn->send(buffer, size);
		}

		void SendMsgToClient(int sessionID, Stream& st)
		{
			if(!m_Active)
				return;
			if (st.size() <= 0) return ;
			TcpConnection conn = m_TcpService->findConn(sessionID);

			if(conn.get() == nullptr)
				return;
			conn->send(&st[0], st.size());
		}

		void SendToHall( Stream& st )
		{
			if(!m_Active)
				return;
			TcpConnection conn = m_TcpService->findConn(-1);
			if(conn.get() == nullptr)
				return;
			conn->send( &st[0], st.size() );
		}

		void SendToHall( const void * buffer, UInt16 size )
		{
			if(!m_Active)
				return;
			TcpConnection conn = m_TcpService->findConn(-1);
			if(conn.get() == nullptr)
				return;
			conn->send( buffer, size );
		}

		void SendToLog( const void * buffer, int size )
		{
			if(!m_Active)
				return;
			TcpConnection conn = m_TcpService->findConn(-2);
			if(conn.get() == nullptr)
				return;
			conn->send( buffer, size );
		}

		void Broadcast(const void * buffer, int size)
		{
			if(!m_Active)
				return;
			m_TcpService->broadcast(buffer, size);
		}

		template <typename PredType>
		void Broadcast(const void * buffer, int size, PredType pred)
		{
			if(!m_Active)
				return;
			m_TcpService->broadcast(buffer, size, pred);
		}

		void Broadcast(Stream& st)
		{
			if(!m_Active)
				return;
			m_TcpService->broadcast(&st[0], st.size());
		}

		template <typename PredType>
		void Broadcast( Stream& st, PredType pred )
		{
			if(!m_Active)
				return;
			m_TcpService->broadcast(&st[0], st.size(), pred);
		}

		template<typename ConduitType, typename PredType, typename DataType>
		void Enumerate( PredType pred, DataType data )
		{
			if(!m_Active)
				return;
			m_TcpService->enumerate<ConduitType>(pred, data);
		}

		UInt32 getOnlineNum()
		{
			if(!m_Active)
				return 0;
			return m_TcpService->getCount();
		}

	private:
		bool m_Active;
		Thread m_TcpThread;
		TcpMasterServerT<Network::GameClient, TcpSlaveWrapper>* m_TcpService;
	};
}

#endif
